#include "Mouse.h"

Mouse::Mouse()
{
	DirectInput = NULL;
	MouseDevice = NULL;

	DX = 0;
	DY = 0;
	DZ = 0;
}

Mouse::~Mouse()
{
	// Empty
}


bool Mouse::Setup(HWND Window, bool Exclusive )
{
	DWORD Flags;

	Shutdown();

	if(FAILED(DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, reinterpret_cast<VOID**>(&DirectInput), NULL)))
	{
		Error::Instance().SetMessage("Unable to create a DirectInput object!");
		return FALSE;
	}

	if(FAILED(DirectInput->CreateDevice(GUID_SysMouse, &MouseDevice, NULL)))
	{
		Error::Instance().SetMessage("Unable to create a DirectInput mouse device!");
		return FALSE;
	}

	if(FAILED(MouseDevice->SetDataFormat(&c_dfDIMouse2)))
	{
		Error::Instance().SetMessage("Unable to set the DirectInput mouse data format!");
		return FALSE;
	}

	Flags = DISCL_FOREGROUND | (Exclusive ? DISCL_EXCLUSIVE : DISCL_NONEXCLUSIVE);

	if(FAILED(MouseDevice->SetCooperativeLevel(Window, Flags)))
	{
		Error::Instance().SetMessage("Unable to set the DirectInput mouse cooperative level!");
		return FALSE;
	}

	MouseDevice->Acquire();

	return TRUE;
}

VOID Mouse::Shutdown()
{
	if(MouseDevice != NULL) 
	{
		MouseDevice->Unacquire();
		MouseDevice->Release();
		MouseDevice = NULL;
	}

	if(DirectInput != NULL)
	{
		DirectInput->Release();
		DirectInput = NULL;
	}

	DX = 0;
	DY = 0;
	DZ = 0;
}

VOID Mouse::Update()
{
	INT i;
	DIMOUSESTATE2 MouseState;

	if(MouseDevice == NULL) return;

	ZeroMemory(&MouseState, sizeof(DIMOUSESTATE2));
	if(FAILED(MouseDevice->GetDeviceState(sizeof(DIMOUSESTATE2), &MouseState)))
	{
		MouseDevice->Acquire();

		ZeroMemory(&MouseState, sizeof(DIMOUSESTATE2));
		if(FAILED(MouseDevice->GetDeviceState(sizeof(DIMOUSESTATE2), &MouseState)))
		{
			return;
		}
	}

	DX = MouseState.lX;
	DY = MouseState.lY;
	DZ = MouseState.lZ;

	AnyButtonState = MouseButtonState();

	for(i = 0; i < NR_OF_MOUSE_BUTTONS; i++)
	{
		ButtonState[i].mButtonPressed = FALSE;
		ButtonState[i].mButtonReleased = FALSE;

		if(MouseState.rgbButtons[i])
		{
			if(!ButtonState[i].mButtonDown)
			{
				ButtonState[i].mButtonPressed = TRUE;
				AnyButtonState.mButtonPressed = TRUE;
			}

			ButtonState[i].mButtonDown = TRUE;
			AnyButtonState.mButtonDown = TRUE;
		}
		else
		{
			if(ButtonState[i].mButtonDown)
			{
				ButtonState[i].mButtonReleased = TRUE;
				AnyButtonState.mButtonReleased = TRUE;
			}

			ButtonState[i].mButtonDown = FALSE;
		}
	}
}


bool Mouse::ButtonDown(u32 Button) const
{
	if(!ValidButton(Button)) return false;

	return ButtonState[Button].mButtonDown;
}

bool Mouse::ButtonPressed(u32 Button) const
{
	if(!ValidButton(Button)) return FALSE;

	return ButtonState[Button].mButtonPressed;
}

bool Mouse::ButtonReleased(u32 Button) const
{
	if(!ValidButton(Button)) return FALSE;

	return ButtonState[Button].mButtonReleased;
}


bool Mouse::AnyButtonDown() const
{
	return AnyButtonState.mButtonDown;
}

bool Mouse::AnyButtonPressed() const
{
	return AnyButtonState.mButtonPressed;
}

bool Mouse::AnyButtonReleased() const
{
	return AnyButtonState.mButtonReleased;
}


s32 Mouse::GetDX() const
{
	return DX;
}

s32 Mouse::GetDY() const
{
	return DY;
}

s32 Mouse::GetDZ() const
{
	return DZ;
}


bool Mouse::ValidButton(u32 Button) const
{
	return (Button >= 0) && (Button < NR_OF_MOUSE_BUTTONS);
}
